package simpleTicTacToe;

import gui.ComputerplayerPanel;
import gui.ConfigPanel;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Shape;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.RoundRectangle2D;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;

import miniMax.TicTacToeFramework;
import actionListener.ButtonListener;
import actionListener.SimpleListener;
import controller.Controlleriface;

public class SimpleGame extends JFrame {

	TicTacToeFramework model;
	Controlleriface controller;

	private static final long serialVersionUID = 1L;

	/* The IDs of the buttons as key, the value are the nine buttons */
	private Map<Integer, JButton> buttons = new HashMap<Integer, JButton>();

	private Color backGroundColor = new Color(150, 150, 190);
	private Border raisedbevel = BorderFactory.createLineBorder(
			backGroundColor, 4);

	/* The panel with the 9 buttons */
	private JPanel tttPanel;

	/* Some sub-panels */
	private JPanel mainPanel = new JPanel(true);
	private JPanel centerPanel = new JPanel(true);
	private JPanel westPanel = new JPanel(true);
	private JPanel eastPanel = new JPanel(true);
	private JPanel northPanel = new JPanel(true);
	/* The panel for the nameLabel with the player informations */
	private JPanel southPanel = new JPanel(true);
	private JPanel buttonPanel = new JPanel(true);
	private JPanel fillPanel = new JPanel(true);
	private ConfigPanel configPanel = new ConfigPanel(backGroundColor);

	public void actualizeWinStat(int[] wins) {
		configPanel.actualizeWinStat(wins);
		validate();
	}

	private JButton restart = new JButton("Neues Spiel");
	private JButton start = new JButton("Spiel starten");
	private JButton close = new JButton("Beenden");

	/* The "special" panels for the Player-data */
	private ComputerplayerPanel cppWest;
	private ComputerplayerPanel cppEast;

	private Shape shape = new RoundRectangle2D.Double(0, 0, 800, 450, 50, 50);
	// Class and method are discovered using reflection
	private Class<?> utils;
	private Method shapeMethod, transparencyMethod;

	/*
	 * The infopanel, which shows the name of the actual player and the
	 * win-situation
	 */
	private JTextField nameLabel = new JTextField();

	/* The constructor */
	public SimpleGame(Controlleriface controller, TicTacToeFramework model) {

		this.controller = controller;
		/* Add the oberserver to the model. There is no other connection */
		this.model = model;
		// model.addObserver(this);

		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {
			e.printStackTrace();
		}

		setLocationRelativeTo(null);
		setUndecorated(true);
		initTicTacToe();
		final Point point = new Point(0, 0);
		northPanel.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				if (!e.isMetaDown()) {
					point.x = e.getX();
					point.y = e.getY();
				}
			}
		});
		northPanel.addMouseMotionListener(new MouseMotionAdapter() {
			public void mouseDragged(MouseEvent e) {
				if (!e.isMetaDown()) {
					Point p = getLocation();
					setLocation(p.x + e.getX() - point.x, p.y + e.getY()
							- point.y);
				}
			}
		});

		// discover if utilities class and methods are available on the
		// system...
		try {
			utils = Class.forName("com.sun.awt.AWTUtilities");
			// method to change a window's shape
			shapeMethod = utils.getMethod("setWindowShape", Window.class,
					Shape.class);
			shapeMethod.invoke(null, this, shape);
			// method to change transparency of a window
			transparencyMethod = utils.getMethod("setWindowOpacity",
					Window.class, float.class);
			transparencyMethod.invoke(null, this, .9f);
		}

		catch (Exception e) {
			System.out
					.println("Class or method has not been found. Make sure that Java1.6_10 JRE is installed on your machine!");
			// System.exit(1);
		}
		
		

		setSize(750, 400);
		setVisible(true);
	}

	public int getIndex(JButton source) {
		Set<Integer> buttonSet = getButtons().keySet();
		for (Integer integer : buttonSet) {
			if (getButtons().get(integer).equals(source)) {
				return integer;
			}
		}
		return -1;
	}

	public boolean getOneCheckbox() {
		return configPanel.getStartWithOneCheck().isSelected();
	}

	public boolean getTwoCheckbox() {
		return configPanel.getStartWithTwoCheck().isSelected();
	}

	/* ################ GUI INITIALIZATION ################ */

	/**
	 * Do the lower gui operations. Init every needed panel and set them
	 * together
	 */
	private void initTicTacToe() {
		setSize(300, 300);
		setLayout(new BorderLayout(5, 5));
		initMainPanel();
		add(mainPanel);
		setBackground(backGroundColor);
		pack();
	}

	private void initButtonPanel() {
		buttonPanel.setLayout(new GridLayout(1, 3));
		buttonPanel.setPreferredSize(new Dimension(250, 60));
		buttonPanel.add(getStart());
		buttonPanel.add(getRestart());
		buttonPanel.add(getClose());
		/* Button ToolTips */
		getStart().setToolTipText("Neue Spieler, neue Stats");
		getRestart().setToolTipText("Gleiche Spieler, neues Spiel");
	}

	private void initSouthPanel() {
		nameLabel = new JTextField();
		setNameLabelText("Warte auf Start . . .");
		nameLabel.setFont(new Font("Serif", Font.BOLD, 14));
		nameLabel.setForeground(Color.BLACK);
		nameLabel.setBackground(backGroundColor);
		nameLabel.setEditable(false);
		nameLabel.setPreferredSize(new Dimension(this.getWidth() - 30, 60));
		nameLabel.setLayout(new FlowLayout(FlowLayout.CENTER));
		nameLabel.setAlignmentX(CENTER_ALIGNMENT);
		initButtonPanel();
		southPanel.setLayout(new BorderLayout(0, 1));
		southPanel.setBorder(BorderFactory.createEtchedBorder());
		southPanel.setBackground(backGroundColor);
		southPanel.add(nameLabel, BorderLayout.NORTH);
		southPanel.add(buttonPanel, BorderLayout.CENTER);
		southPanel.add(configPanel, BorderLayout.SOUTH);
	}

	private void initEastPanel() {
		setCppEast(new ComputerplayerPanel(this));
		eastPanel.setLayout(new BorderLayout());
		eastPanel.add(getCppEast(), BorderLayout.CENTER);
		JPanel fillPanel = new JPanel();
		fillPanel.setBackground(backGroundColor);
		eastPanel.add(fillPanel, BorderLayout.EAST);
		eastPanel.setPreferredSize(new Dimension(250, 60));

	}

	private void initNorthPanel() {
		JTextArea nameLabel = new JTextArea(" TIC TAC TOE ");
		nameLabel.setAlignmentX(CENTER_ALIGNMENT);
		nameLabel.setFont(new Font("Serif", Font.BOLD, 25));
		nameLabel.setBorder(raisedbevel);
		nameLabel.setEditable(false);
		nameLabel.setBackground(backGroundColor);
		JPanel namePanel = new JPanel();
		namePanel.setBorder(raisedbevel);
		namePanel.add(nameLabel);
		northPanel.setBackground(backGroundColor);
		northPanel.add(namePanel);
	}

	private void initWestPanel() {
		setCppWest(new ComputerplayerPanel(this));
		westPanel.setLayout(new BorderLayout());
		westPanel.add(getCppWest(), BorderLayout.CENTER);
		westPanel.add(fillPanel, BorderLayout.WEST);
		westPanel.setPreferredSize(new Dimension(250, 60));
	}

	private void initMainPanel() {
		fillPanel.setBackground(backGroundColor);
		initTttPanel();
		initEastPanel();
		initWestPanel();
		initNorthPanel();
		initSouthPanel();
		mainPanel.setLayout(new GridLayout(1, 1));
		centerPanel.setLayout(new BorderLayout(5, 5));
		centerPanel.add(tttPanel, BorderLayout.CENTER);
		centerPanel.add(eastPanel, BorderLayout.EAST);
		centerPanel.add(westPanel, BorderLayout.WEST);
		centerPanel.add(northPanel, BorderLayout.NORTH);
		centerPanel.add(southPanel, BorderLayout.SOUTH);
		centerPanel.setBackground(backGroundColor);
		// centerPanel.setPreferredSize(new Dimension(700, 350));
		mainPanel.add(centerPanel);
	}

	private void initTttPanel() {
		initButtons(model);
		tttPanel = new JPanel(new GridLayout(3, 3));
		tttPanel.setBackground(backGroundColor);
		Set<Integer> buttonSet = getButtons().keySet();
		List<Integer> buttonSorted = new LinkedList<Integer>(buttonSet);
		Collections.sort(buttonSorted);
		for (Integer button : buttonSorted) {
			tttPanel.add(getButtons().get(button));
		}
	}

	public void setNameLabelText(String text) {
		nameLabel.setText(fillWithBlanks(text));
	}

	public final void initButtons(final TicTacToeFramework model) {
		for (int i = 0; i < model.getGameField().length; i++) {
			for (int j = 0; j < model.getGameField().length; j++) {
				final JButton jb = new JButton(" ");
				jb.setMinimumSize(new Dimension(50, 50));
				jb.setPreferredSize(new Dimension(50, 50));
				jb.addActionListener(new SimpleListener(model, controller));
				int id = map2dToId(i, j);
				jb.setFont(new Font("Serif", Font.BOLD, 20));
				jb.setText(model.getGameField()[i][j]);
				getButtons().put(id, jb);
			}
		}

		start.addActionListener(new ButtonListener(controller));
		restart.addActionListener(new ButtonListener(controller));
		close.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				nameLabel.setText(fillWithBlanks("Spiel wird beendet."));
				new Timer().schedule(new TimerTask() {

					@Override
					public void run() {
						System.exit(0);
					}
				}, 1000);

			}
		});
		validate();

	}

	private final void rewriteButtons(TicTacToeFramework model) {
		for (int i = 0; i < model.getGameField().length; i++) {
			for (int j = 0; j < model.getGameField().length; j++) {
				JButton jb = getButtons().get(map2dToId(i, j));
					jb.setText(model.getGameField()[i][j]);
			}
		}
	}

	private int map2dToId(int row, int col) {
		return (row * 3) + (col + 1);
	}

	private String fillWithBlanks(String text) {
		return "\t\t" + text;
	}

	public void actualize(TicTacToeFramework model) {
		this.model = model;
		rewriteButtons(model);
		validate();
	}

	public void update(Object arg) {
		rewriteButtons(model);
		validate();
	}

	public void deactivate() {
		Set<Integer> buttonSet = getButtons().keySet();
		for (Integer integer : buttonSet) {
			JButton jb = getButtons().get(integer);
			jb.setEnabled(false);
		}
	}

	public void activate() {
		Set<Integer> buttonSet = getButtons().keySet();
		for (Integer integer : buttonSet) {
			JButton jb = getButtons().get(integer);
			jb.setEnabled(true);
		}
	}

	/* ############# SETTER & GETTER ############## */

	public JButton getStart() {
		return start;
	}

	public void setStart(JButton start) {
		this.start = start;
	}

	public ComputerplayerPanel getCppWest() {
		return cppWest;
	}

	public void setCppWest(ComputerplayerPanel cppWest) {
		this.cppWest = cppWest;
	}

	public ComputerplayerPanel getCppEast() {
		return cppEast;
	}

	public void setCppEast(ComputerplayerPanel cppEast) {
		this.cppEast = cppEast;
	}

	public JButton getClose() {
		return close;
	}

	public void setClose(JButton close) {
		this.close = close;
	}

	public JButton getRestart() {
		return restart;
	}

	public void setNameLabel(String string) {
		setNameLabelText(string);
	}

	public void setButtons(Map<Integer, JButton> buttons) {
		this.buttons = buttons;
	}

	public Map<Integer, JButton> getButtons() {
		return buttons;
	}

}
